package org.easy.amapweather;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.easy.core.exception.BizRuntimeException;
import org.easy.core.util.HttpUtil;
import org.easy.core.util.ObjectUtil;
import lombok.Data;

import java.util.*;
import java.util.stream.Collectors;

/**
 * https://lbs.amap.com/api/webservice/guide/api/weatherinfo
 */
public class AmapWeatherClient {
    private static final Map<String, List<CityAdCode>> cityNameGroup;
    private static final Map<String, Integer> provinceNameAdCodeMap;

    static {
        String string = HttpUtil.sendGet("https://地址编码/adcode.json", null, null);
        List<CityAdCode> cityAdCodes = JSON.parseArray(string, CityAdCode.class);
        cityNameGroup = cityAdCodes.stream().collect(Collectors.groupingBy(CityAdCode::getName));
        provinceNameAdCodeMap = cityAdCodes.stream().filter(e -> e.getAdcode() % 10000 == 0).collect(Collectors.toMap(CityAdCode::getName, CityAdCode::getAdcode));
    }


    /**
     * 高德地图请求地址
     */
    private final static String REQUEST_URL_TEMPLATE = "https://restapi.amap.com/v3/weather/weatherInfo";


    /**
     * 实况天气
     *
     * @param key      请求服务权限标识 https://console.amap.com/dev/key/app 查看key
     * @param province 城市编码 https://a.amap.com/lbs/static/code_resource/AMap_adcode_citycode.zip
     * @param city     城市编码 https://a.amap.com/lbs/static/code_resource/AMap_adcode_citycode.zip
     * @return
     */
    public WeatherLive getNowWeather(String key, String province, String city) {
        Map<String, String> params = new HashMap<>();
        params.put("key", key);
        params.put("city", String.valueOf(cityToAdcode(province, city)));
        params.put("extensions", "base");//返回实况天气
        String response = HttpUtil.sendGet(REQUEST_URL_TEMPLATE, null, params);
        JSONObject jsonObject = JSON.parseObject(response).getJSONArray("lives").getJSONObject(0);
        return JSON.parseObject(jsonObject.toJSONString(), WeatherLive.class);
    }

    /**
     * 未来天气
     *
     * @param key
     * @param province
     * @param city
     * @return
     */
    public List<WeatherCasts> getFeatureWeather(String key, String province, String city) {
        Map<String, String> params = new HashMap<>();
        params.put("key", key);
        params.put("city", String.valueOf(cityToAdcode(province, city)));
        params.put("extensions", "all");//返回预报天气
        String response = HttpUtil.sendGet(REQUEST_URL_TEMPLATE, null, params);
        JSONArray jsonArray = JSON.parseObject(response).getJSONArray("forecasts").getJSONObject(0).getJSONArray("casts");
        return JSON.parseArray(jsonArray.toJSONString(), WeatherCasts.class);
    }


    private static Integer cityToAdcode(String province, String city) {
        List<CityAdCode> queryCity = cityNameGroup.get(city);

        if (ObjectUtil.isEmpty(queryCity)) {
            queryCity = cityNameGroup.get(city + "市");
        }
        if (ObjectUtil.isEmpty(queryCity)) {
            queryCity = cityNameGroup.get(city + "县");
        }
        if (ObjectUtil.isEmpty(queryCity)) {
            queryCity = cityNameGroup.get(city + "区");
        }
        if (ObjectUtil.isEmpty(queryCity)) {
            throw new BizRuntimeException("未知城市");
        }

        //有且仅有一个城市则返回
        if (queryCity.size() == 1) {
            return queryCity.get(0).getAdcode();
        }

        if (ObjectUtil.isEmpty(province)) {
            return queryCity.get(0).getAdcode();
        }

        queryCity = cityNameGroup.get(city).stream().sorted(Comparator.comparing(CityAdCode::getAdcode).reversed()).collect(Collectors.toList());
        Integer provinceAdcode = provinceNameAdCodeMap.get(province);
        if (ObjectUtil.isEmpty(provinceAdcode)) {
            return queryCity.get(0).getAdcode();
        }

        Optional<CityAdCode> min = queryCity.stream().filter(e -> e.getAdcode() > provinceAdcode).min(Comparator.comparing(CityAdCode::getAdcode));
        if (min.isPresent()) {
            return min.get().getAdcode();
        }
        return queryCity.get(0).getAdcode();

    }

    @Data
    public static class CityAdCode {
        private Integer adcode;
        private String citycode;
        private String name;
    }

}